#include <iostream>
#include <findCircleParameter.h>
#include <opencv2/imgproc.hpp>
#include "FishStitcherMain.h"

#include <sstream>

using namespace std;
using namespace cv;

vector<Mat>  vet_imgs;
string          str_output;

void strongImageAlphaAndBeta(const Mat &src_img, Mat &dst_img, double alpha, int beta)
{
    for(int y=0;y<src_img.rows;++y)
    {
        for(int x=0;x<src_img.cols;++x)
        {
            for(int c=0;c<3;c++)
            {
                dst_img.at<Vec3b>(y,x)[c] = saturate_cast<uchar>(alpha * (src_img.at<Vec3b>(y,x)[c] + beta));
            }
        }
    }
}

bool    getcirclepos(Mat  &src_img,Point2i&  center,int& radius )
{
    if(src_img.data == NULL) return false;

    Mat  gray_img;
    cvtColor(src_img,gray_img,CV_BGR2GRAY);

    Mat bin_img;
    threshold(gray_img,bin_img,150,255,THRESH_BINARY);

    Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3));
    morphologyEx(bin_img,bin_img,MORPH_CLOSE,kernel,Point(-1,-1),30);

    Mat  bin_cns_img;
    cvtColor(bin_img,bin_cns_img,CV_GRAY2BGR);

    findCircleParameter::init(bin_cns_img);

    findCircleParameter::findCircle();
    bool bres = findCircleParameter::getCircleParatemer(center,radius);

    cout << "center points:" << center << "radius:" << radius << endl;

    return bres;
}

void    getcircleimg(const Mat  &src_img,const Point2i&  center,const int& radius,Mat& output_img )
{
    Mat roi_img = Mat::zeros(src_img.rows,src_img.cols,CV_8UC1);

    circle(roi_img,center,radius,Scalar(255,255,255),-1,8,0);

    Mat bit_img;
    Mat src_copy = src_img.clone();
    bitwise_and(src_copy,src_copy,bit_img,roi_img);


    bitwise_not(roi_img,roi_img);
    Mat roi_tmp_img = Mat(roi_img.size(),CV_8UC1,Scalar(255));
    add(roi_img,roi_tmp_img,roi_img,roi_img);

    bitwise_not(roi_img,roi_img);
    morphologyEx(roi_img,roi_img,MORPH_OPEN,getStructuringElement(MORPH_RECT,Size(3,3)));


    std::vector<Mat> channels;
    std::vector<Mat> dstChannels;

    Mat r_img,g_img,b_img;
    split(src_copy,channels);
    bitwise_and(channels[0],roi_img,b_img);
    bitwise_and(channels[1],roi_img,g_img);
    bitwise_and(channels[2],roi_img,r_img);

    dstChannels.push_back(b_img);
    dstChannels.push_back(g_img);
    dstChannels.push_back(r_img);

    merge(dstChannels,output_img);
}

bool  input_imagepath(const string& input_img1,const string& input_img2,const string& input_img3,const string& input_img4)
{
    Mat image = imread(input_img1);
    if(image.data == NULL)  return false;
    vet_imgs .push_back( image );

    image = imread(input_img2);
    if(image.data == NULL)  return false;
    vet_imgs .push_back( image );

    image = imread(input_img3);
    if(image.data == NULL)  return false;
    vet_imgs .push_back( image );

    image = imread(input_img4);
    if(image.data == NULL)  return false;
    vet_imgs .push_back( image );

    return true;
}

string g_strbase_path;
string g_strimg_path1 ;
string g_strimg_path2 ;
string g_strimg_path3 ;
string g_strimg_path4 ;
string g_strimg_resultpath ;
bool   g_binpaint = true;
int  g_nimg_hight = 1920;

void PrintUsage()
{
    std::cout << "Usage(cmd)  :  FishEyeCorrect  + [flags]" << std::endl;
    std::cout << "               Flags:" << std::endl;
    std::cout << "               -work_dir work_path" << std::endl;
    std::cout << "                         Use work_path as the work directory." << std::endl;
    std::cout << "               -input image filename" << std::endl;
    std::cout << "                         Set the image filename. " << std::endl;
    std::cout << "               -height height_value" << std::endl;
    std::cout << "                         Set the image height of result. " << std::endl;
    std::cout << "               -reslut name_value" << std::endl;
    std::cout << "                         Set the result name, Default set to 'result.jpg'" << std::endl;
    std::cout << "               -repaint image flag" << std::endl;
    std::cout << "                         Repaint the image flag ,Default set to true'" << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        PrintUsage();
        return 0;
    }

    for (int i = 1; i < argc; i++)
    {
        if (std::string(argv[i]) == "-help" || std::string(argv[i]) == "/?")
        {
            PrintUsage();
            return 0;
        }
        else if (std::string(argv[i]) == "-work_dir")
        {
            g_strbase_path = std::string(argv[i + 1]);
            i++;
            cout << "base path " << g_strbase_path <<endl;
        }
        else if (std::string(argv[i]) == "-height")
        {
            int height = atof(argv[i + 1]);
            g_nimg_hight = height;
            i++;
        }
        else if(std::string(argv[i]) == "-in1")
        {
            g_strimg_path1 = std::string(argv[i + 1]);
            i++;
        }
        else if(std::string(argv[i]) == "-in2")
        {
            g_strimg_path2 = std::string(argv[i + 1]);
            i++;
        }
        else if(std::string(argv[i]) == "-in3")
        {
            g_strimg_path3 = std::string(argv[i + 1]);
            i++;
        }
        else if(std::string(argv[i]) == "-in4")
        {
            g_strimg_path4 = std::string(argv[i + 1]);
            i++;
        }
        else if(std::string(argv[i]) == "-repaint")
        {
            string str = string(argv[i + 1]);

            istringstream(str) >> boolalpha >> g_binpaint;
            i++;
        }
    }

    bool bres = input_imagepath(g_strbase_path + g_strimg_path1,
                                g_strbase_path + g_strimg_path2,
                                g_strbase_path + g_strimg_path3,
                                g_strbase_path + g_strimg_path4);

    if(!bres ) {
        cout << "图片路径不正确，无法读取图片!" << endl;
        return -1;
    }

    Point2i  center;
    int radius;

    bres = getcirclepos(vet_imgs[0],center,radius);
    vector<Mat>  vet_circleimgs;

    if(!bres )
    {
        cout << "无法获取圆心位置!" << endl;
        return -1;
    }

    for(int i=0;i<vet_imgs.size();++i)
    {
        Mat  circle_img;
        getcircleimg(vet_imgs[i],center,radius,circle_img);

        Mat roi_img = circle_img(Rect(center.x-radius,center.y-radius,radius * 2,radius * 2));

        Mat  resize_img;
        resize(roi_img,resize_img,Size(1280,1280));

        Mat org_img = Mat::zeros(1280,1920,CV_8UC3);
        int x = (org_img.cols - 1280) / 2;
        Mat correct_img = org_img(Rect(x,0,1280,1280));
        resize_img.copyTo(correct_img);

        char path[128] = {0};
        sprintf(path,"./circle_%d.jpg",i);
        imwrite(path,correct_img);

        vet_circleimgs.push_back(correct_img);       
    }

    if(vet_circleimgs.size() <= 0) return -1;

    Mat result_img;
    FishStitcherMain(vet_circleimgs,result_img,g_nimg_hight);

    imwrite(g_strbase_path + "/result.jpg",result_img);

    cout << "拼接完成!" <<endl;

    if(g_binpaint == false) return -1;

    result_img = imread(g_strbase_path + "/result.jpg");
    //修复全景图;
    Mat gray_result_img;

    if(result_img.data == NULL)return 0;

    cvtColor(result_img,gray_result_img,CV_BGR2GRAY);

    Mat bin_result_img;
    threshold(gray_result_img,bin_result_img,10,255,THRESH_BINARY);

    blur(bin_result_img,bin_result_img,Size(5,5));

    Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3));

    morphologyEx(bin_result_img,bin_result_img,MORPH_CLOSE,kernel,Point(-1,-1),5);

    bin_result_img = ~bin_result_img;

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(bin_result_img,contours,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE,Point());

    if(contours.size() <= 0) return -1;

    Mat   inpainted_image = result_img.clone();
    for(int i=0;i<contours.size();++i)
    {
         Mat   roi_result_img = bin_result_img(boundingRect(contours[i]));
         Mat   inpaint_mask = Mat::zeros(inpainted_image.size(), CV_8UC1);

         Mat inpaint_roi_mask = inpaint_mask(boundingRect(contours[i]));
         roi_result_img.copyTo(inpaint_roi_mask);

         inpaint(inpainted_image, inpaint_mask, inpainted_image, 10, CV_INPAINT_TELEA);
    }

    imwrite(g_strbase_path + "/result.jpg",inpainted_image);

    cout << "图片修复完成!" <<endl;

    return 0;
}
